using Dapper;
using MediatR;
using Microsoft.Extensions.Logging;
using RBAC.Domain.PurchasingManagement.PurchaseOrders;
using RBAC.ErrorCode;
using RBAC.Interstructrue.Base;
using RBAC.Write.Api.Application.Command.ERP.PurchasingManagement.PurchaseOrders;
using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

namespace RBAC.Write.Api.Application.Handler.ERP.PurchasingManagement.PurchaseOrders
{
    /// <summary>
    /// 编辑采购订单（主表 + 可选重置明细）
    /// </summary>
    public class UpdatePurchaseOrderCommandHandler : IRequestHandler<UpdatePurchaseOrderCommand, APIResult<int>>
    {
        private readonly IBaseRepository<PurchaseOrderInfo> _repo;
        private readonly IDbConnectionFactory _connectionFactory;
        private readonly ILogger<UpdatePurchaseOrderCommandHandler> _logger;

        public UpdatePurchaseOrderCommandHandler(
            IBaseRepository<PurchaseOrderInfo> repo,
            IDbConnectionFactory connectionFactory,
            ILogger<UpdatePurchaseOrderCommandHandler> logger)
        {
            _repo = repo;
            _connectionFactory = connectionFactory;
            _logger = logger;
        }

        public Task<APIResult<int>> Handle(UpdatePurchaseOrderCommand request, CancellationToken cancellationToken)
        {
            var res = new APIResult<int>();
            try
            {
                if (request.Id <= 0)
                {
                    return Task.FromResult(new APIResult<int> { Code = APIEnums.Fail, Msg = "主键Id不能为空", Data = 0 });
                }
                if (string.IsNullOrWhiteSpace(request.DocCode))
                {
                    return Task.FromResult(new APIResult<int> { Code = APIEnums.Fail, Msg = "单据编码不能为空", Data = 0 });
                }
                if (string.IsNullOrWhiteSpace(request.supplierId))
                {
                    return Task.FromResult(new APIResult<int> { Code = APIEnums.Fail, Msg = "供应商ID不能为空", Data = 0 });
                }

                // 唯一性校验（DocCode 排除自身）
                var dup = _repo.GetFirstOrDefault("DocCode = @DocCode AND Id <> @Id", new { request.DocCode, request.Id });
                if (dup != null)
                {
                    return Task.FromResult(new APIResult<int> { Code = APIEnums.Fail, Msg = "单据编码已存在", Data = 0 });
                }

                var entity = _repo.GetModel(request.Id);
                if (entity == null || entity.IsDeleted)
                {
                    return Task.FromResult(new APIResult<int> { Code = APIEnums.Fail, Msg = "记录不存在", Data = 0 });
                }

                // 映射可编辑字段
                entity.DocCode = request.DocCode;
                entity.BizType = request.BizType;
                entity.Operatorer = request.Operatorer;
                entity.supplierId = request.supplierId;
                entity.docDate = request.docDate;
                entity.docType = request.docType;
                entity.arrivalDate = request.arrivalDate;
                entity.docStatus = request.docStatus;
                entity.purchaseDept = request.purchaseDept;
                entity.auditDate = request.auditDate;
                entity.contractUpload = request.contractUpload;
                entity.bizStatus = request.bizStatus;
                entity.purchaser = request.purchaser;
                entity.materialDemand = request.materialDemand;
                entity.contractNo = request.contractNo;
                entity.remark = request.remark;

                var aff = _repo.Update(entity);

                // 若未带明细，则仅更新主表
                if (request.Details == null)
                {
                    res.Code = aff > 0 ? APIEnums.Success : APIEnums.Fail;
                    res.Msg = aff > 0 ? "编辑采购订单成功" : "编辑采购订单失败";
                    res.Data = aff;
                    return Task.FromResult(res);
                }

                // 重置明细：删除后再插入
                try
                {
                    using var conn = _connectionFactory.CreateConnectionWithRetry();
                    using var tran = conn.BeginTransaction();

                    var delSql = "DELETE FROM PurchasingMaterialInfo WHERE PurchaseOrderId = @PurchaseOrderId";
                    conn.Execute(delSql, new { PurchaseOrderId = request.Id }, tran);

                    var insSql = @"INSERT INTO PurchasingMaterialInfo
                                    (PurchaseOrderId, DocumentaryNumber, PlannedOrderNumber, materialCode, materialName, modelSpec, mainUnit,
                                     demandDate, qty, unitPrice, amount, arrivalQty, PurchasingInstructions, IsDel)
                                    VALUES
                                    (@PurchaseOrderId, @DocumentaryNumber, @PlannedOrderNumber, @materialCode, @materialName, @modelSpec, @mainUnit,
                                     @demandDate, @qty, @unitPrice, @amount, @arrivalQty, @PurchasingInstructions, @IsDel);";

                    foreach (var d in request.Details)
                    {
                        var p = new
                        {
                            PurchaseOrderId = request.Id,
                            DocumentaryNumber = d.DocumentaryNumber,
                            PlannedOrderNumber = d.PlannedOrderNumber,
                            materialCode = d.materialCode,
                            materialName = d.materialName,
                            modelSpec = d.modelSpec,
                            mainUnit = d.mainUnit,
                            demandDate = d.demandDate,
                            qty = d.qty,
                            unitPrice = d.unitPrice,
                            amount = (d.amount.HasValue && d.amount.Value > 0) ? d.amount.Value : d.unitPrice * d.qty,
                            arrivalQty = d.arrivalQty,
                            PurchasingInstructions = d.PurchasingInstructions,
                            IsDel = false
                        };
                        conn.Execute(insSql, p, tran);
                    }

                    tran.Commit();
                }
                catch (Exception ex)
                {
                    _logger.LogError(ex, "重置采购订单明细失败: {Message}", ex.Message);
                    // 明细失败不回滚主表，如需强一致性可抛出异常让上层事务处理
                }

                res.Code = aff > 0 ? APIEnums.Success : APIEnums.Fail;
                res.Msg = aff > 0 ? "编辑采购订单成功" : "编辑采购订单失败";
                res.Data = aff;
            }
            catch (Exception ex)
            {
                res.Code = APIEnums.Error;
                res.Msg = "编辑采购订单异常";
                _logger.LogError(ex, "编辑采购订单异常: {Message}", ex.Message);
            }

            return Task.FromResult(res);
        }
    }
}
